﻿/********************************************************************
	created:	2011-8-14   16:06
	author:		Lifan Su
	
	purpose:	implement of CRC-64 functions,
                based on PostgreSQL 64-bit CRC support
*********************************************************************/

//
// Excerpt of license
//
/*
PostgreSQL Data Base Management System

Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group 
Portions Copyright (c) 1994-1996 Regents of the University of California

Permission to use, copy, modify, and distribute this software and its 
documentation for any purpose, without fee, and without a written agreement 
is hereby granted, provided that the above copyright notice and this 
paragraph and the following two paragraphs appear in all copies.

IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR 
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING 
LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, 
EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.

THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 
ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS 
TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/

#include "crc64.h"
#include <cvt_int_mem.h>
#include "hex_to_char.h"

#include <assert.h>
#include <_stdint.h>


static const uint64_t crc64_table[256] = {
    UINT64_C(0x0000000000000000), UINT64_C(0x42F0E1EBA9EA3693),
    UINT64_C(0x85E1C3D753D46D26), UINT64_C(0xC711223CFA3E5BB5),
    UINT64_C(0x493366450E42ECDF), UINT64_C(0x0BC387AEA7A8DA4C),
    UINT64_C(0xCCD2A5925D9681F9), UINT64_C(0x8E224479F47CB76A),
    UINT64_C(0x9266CC8A1C85D9BE), UINT64_C(0xD0962D61B56FEF2D),
    UINT64_C(0x17870F5D4F51B498), UINT64_C(0x5577EEB6E6BB820B),
    UINT64_C(0xDB55AACF12C73561), UINT64_C(0x99A54B24BB2D03F2),
    UINT64_C(0x5EB4691841135847), UINT64_C(0x1C4488F3E8F96ED4),
    UINT64_C(0x663D78FF90E185EF), UINT64_C(0x24CD9914390BB37C),
    UINT64_C(0xE3DCBB28C335E8C9), UINT64_C(0xA12C5AC36ADFDE5A),
    UINT64_C(0x2F0E1EBA9EA36930), UINT64_C(0x6DFEFF5137495FA3),
    UINT64_C(0xAAEFDD6DCD770416), UINT64_C(0xE81F3C86649D3285),
    UINT64_C(0xF45BB4758C645C51), UINT64_C(0xB6AB559E258E6AC2),
    UINT64_C(0x71BA77A2DFB03177), UINT64_C(0x334A9649765A07E4),
    UINT64_C(0xBD68D2308226B08E), UINT64_C(0xFF9833DB2BCC861D),
    UINT64_C(0x388911E7D1F2DDA8), UINT64_C(0x7A79F00C7818EB3B),
    UINT64_C(0xCC7AF1FF21C30BDE), UINT64_C(0x8E8A101488293D4D),
    UINT64_C(0x499B3228721766F8), UINT64_C(0x0B6BD3C3DBFD506B),
    UINT64_C(0x854997BA2F81E701), UINT64_C(0xC7B97651866BD192),
    UINT64_C(0x00A8546D7C558A27), UINT64_C(0x4258B586D5BFBCB4),
    UINT64_C(0x5E1C3D753D46D260), UINT64_C(0x1CECDC9E94ACE4F3),
    UINT64_C(0xDBFDFEA26E92BF46), UINT64_C(0x990D1F49C77889D5),
    UINT64_C(0x172F5B3033043EBF), UINT64_C(0x55DFBADB9AEE082C),
    UINT64_C(0x92CE98E760D05399), UINT64_C(0xD03E790CC93A650A),
    UINT64_C(0xAA478900B1228E31), UINT64_C(0xE8B768EB18C8B8A2),
    UINT64_C(0x2FA64AD7E2F6E317), UINT64_C(0x6D56AB3C4B1CD584),
    UINT64_C(0xE374EF45BF6062EE), UINT64_C(0xA1840EAE168A547D),
    UINT64_C(0x66952C92ECB40FC8), UINT64_C(0x2465CD79455E395B),
    UINT64_C(0x3821458AADA7578F), UINT64_C(0x7AD1A461044D611C),
    UINT64_C(0xBDC0865DFE733AA9), UINT64_C(0xFF3067B657990C3A),
    UINT64_C(0x711223CFA3E5BB50), UINT64_C(0x33E2C2240A0F8DC3),
    UINT64_C(0xF4F3E018F031D676), UINT64_C(0xB60301F359DBE0E5),
    UINT64_C(0xDA050215EA6C212F), UINT64_C(0x98F5E3FE438617BC),
    UINT64_C(0x5FE4C1C2B9B84C09), UINT64_C(0x1D14202910527A9A),
    UINT64_C(0x93366450E42ECDF0), UINT64_C(0xD1C685BB4DC4FB63),
    UINT64_C(0x16D7A787B7FAA0D6), UINT64_C(0x5427466C1E109645),
    UINT64_C(0x4863CE9FF6E9F891), UINT64_C(0x0A932F745F03CE02),
    UINT64_C(0xCD820D48A53D95B7), UINT64_C(0x8F72ECA30CD7A324),
    UINT64_C(0x0150A8DAF8AB144E), UINT64_C(0x43A04931514122DD),
    UINT64_C(0x84B16B0DAB7F7968), UINT64_C(0xC6418AE602954FFB),
    UINT64_C(0xBC387AEA7A8DA4C0), UINT64_C(0xFEC89B01D3679253),
    UINT64_C(0x39D9B93D2959C9E6), UINT64_C(0x7B2958D680B3FF75),
    UINT64_C(0xF50B1CAF74CF481F), UINT64_C(0xB7FBFD44DD257E8C),
    UINT64_C(0x70EADF78271B2539), UINT64_C(0x321A3E938EF113AA),
    UINT64_C(0x2E5EB66066087D7E), UINT64_C(0x6CAE578BCFE24BED),
    UINT64_C(0xABBF75B735DC1058), UINT64_C(0xE94F945C9C3626CB),
    UINT64_C(0x676DD025684A91A1), UINT64_C(0x259D31CEC1A0A732),
    UINT64_C(0xE28C13F23B9EFC87), UINT64_C(0xA07CF2199274CA14),
    UINT64_C(0x167FF3EACBAF2AF1), UINT64_C(0x548F120162451C62),
    UINT64_C(0x939E303D987B47D7), UINT64_C(0xD16ED1D631917144),
    UINT64_C(0x5F4C95AFC5EDC62E), UINT64_C(0x1DBC74446C07F0BD),
    UINT64_C(0xDAAD56789639AB08), UINT64_C(0x985DB7933FD39D9B),
    UINT64_C(0x84193F60D72AF34F), UINT64_C(0xC6E9DE8B7EC0C5DC),
    UINT64_C(0x01F8FCB784FE9E69), UINT64_C(0x43081D5C2D14A8FA),
    UINT64_C(0xCD2A5925D9681F90), UINT64_C(0x8FDAB8CE70822903),
    UINT64_C(0x48CB9AF28ABC72B6), UINT64_C(0x0A3B7B1923564425),
    UINT64_C(0x70428B155B4EAF1E), UINT64_C(0x32B26AFEF2A4998D),
    UINT64_C(0xF5A348C2089AC238), UINT64_C(0xB753A929A170F4AB),
    UINT64_C(0x3971ED50550C43C1), UINT64_C(0x7B810CBBFCE67552),
    UINT64_C(0xBC902E8706D82EE7), UINT64_C(0xFE60CF6CAF321874),
    UINT64_C(0xE224479F47CB76A0), UINT64_C(0xA0D4A674EE214033),
    UINT64_C(0x67C58448141F1B86), UINT64_C(0x253565A3BDF52D15),
    UINT64_C(0xAB1721DA49899A7F), UINT64_C(0xE9E7C031E063ACEC),
    UINT64_C(0x2EF6E20D1A5DF759), UINT64_C(0x6C0603E6B3B7C1CA),
    UINT64_C(0xF6FAE5C07D3274CD), UINT64_C(0xB40A042BD4D8425E),
    UINT64_C(0x731B26172EE619EB), UINT64_C(0x31EBC7FC870C2F78),
    UINT64_C(0xBFC9838573709812), UINT64_C(0xFD39626EDA9AAE81),
    UINT64_C(0x3A28405220A4F534), UINT64_C(0x78D8A1B9894EC3A7),
    UINT64_C(0x649C294A61B7AD73), UINT64_C(0x266CC8A1C85D9BE0),
    UINT64_C(0xE17DEA9D3263C055), UINT64_C(0xA38D0B769B89F6C6),
    UINT64_C(0x2DAF4F0F6FF541AC), UINT64_C(0x6F5FAEE4C61F773F),
    UINT64_C(0xA84E8CD83C212C8A), UINT64_C(0xEABE6D3395CB1A19),
    UINT64_C(0x90C79D3FEDD3F122), UINT64_C(0xD2377CD44439C7B1),
    UINT64_C(0x15265EE8BE079C04), UINT64_C(0x57D6BF0317EDAA97),
    UINT64_C(0xD9F4FB7AE3911DFD), UINT64_C(0x9B041A914A7B2B6E),
    UINT64_C(0x5C1538ADB04570DB), UINT64_C(0x1EE5D94619AF4648),
    UINT64_C(0x02A151B5F156289C), UINT64_C(0x4051B05E58BC1E0F),
    UINT64_C(0x87409262A28245BA), UINT64_C(0xC5B073890B687329),
    UINT64_C(0x4B9237F0FF14C443), UINT64_C(0x0962D61B56FEF2D0),
    UINT64_C(0xCE73F427ACC0A965), UINT64_C(0x8C8315CC052A9FF6),
    UINT64_C(0x3A80143F5CF17F13), UINT64_C(0x7870F5D4F51B4980),
    UINT64_C(0xBF61D7E80F251235), UINT64_C(0xFD913603A6CF24A6),
    UINT64_C(0x73B3727A52B393CC), UINT64_C(0x31439391FB59A55F),
    UINT64_C(0xF652B1AD0167FEEA), UINT64_C(0xB4A25046A88DC879),
    UINT64_C(0xA8E6D8B54074A6AD), UINT64_C(0xEA16395EE99E903E),
    UINT64_C(0x2D071B6213A0CB8B), UINT64_C(0x6FF7FA89BA4AFD18),
    UINT64_C(0xE1D5BEF04E364A72), UINT64_C(0xA3255F1BE7DC7CE1),
    UINT64_C(0x64347D271DE22754), UINT64_C(0x26C49CCCB40811C7),
    UINT64_C(0x5CBD6CC0CC10FAFC), UINT64_C(0x1E4D8D2B65FACC6F),
    UINT64_C(0xD95CAF179FC497DA), UINT64_C(0x9BAC4EFC362EA149),
    UINT64_C(0x158E0A85C2521623), UINT64_C(0x577EEB6E6BB820B0),
    UINT64_C(0x906FC95291867B05), UINT64_C(0xD29F28B9386C4D96),
    UINT64_C(0xCEDBA04AD0952342), UINT64_C(0x8C2B41A1797F15D1),
    UINT64_C(0x4B3A639D83414E64), UINT64_C(0x09CA82762AAB78F7),
    UINT64_C(0x87E8C60FDED7CF9D), UINT64_C(0xC51827E4773DF90E),
    UINT64_C(0x020905D88D03A2BB), UINT64_C(0x40F9E43324E99428),
    UINT64_C(0x2CFFE7D5975E55E2), UINT64_C(0x6E0F063E3EB46371),
    UINT64_C(0xA91E2402C48A38C4), UINT64_C(0xEBEEC5E96D600E57),
    UINT64_C(0x65CC8190991CB93D), UINT64_C(0x273C607B30F68FAE),
    UINT64_C(0xE02D4247CAC8D41B), UINT64_C(0xA2DDA3AC6322E288),
    UINT64_C(0xBE992B5F8BDB8C5C), UINT64_C(0xFC69CAB42231BACF),
    UINT64_C(0x3B78E888D80FE17A), UINT64_C(0x7988096371E5D7E9),
    UINT64_C(0xF7AA4D1A85996083), UINT64_C(0xB55AACF12C735610),
    UINT64_C(0x724B8ECDD64D0DA5), UINT64_C(0x30BB6F267FA73B36),
    UINT64_C(0x4AC29F2A07BFD00D), UINT64_C(0x08327EC1AE55E69E),
    UINT64_C(0xCF235CFD546BBD2B), UINT64_C(0x8DD3BD16FD818BB8),
    UINT64_C(0x03F1F96F09FD3CD2), UINT64_C(0x41011884A0170A41),
    UINT64_C(0x86103AB85A2951F4), UINT64_C(0xC4E0DB53F3C36767),
    UINT64_C(0xD8A453A01B3A09B3), UINT64_C(0x9A54B24BB2D03F20),
    UINT64_C(0x5D45907748EE6495), UINT64_C(0x1FB5719CE1045206),
    UINT64_C(0x919735E51578E56C), UINT64_C(0xD367D40EBC92D3FF),
    UINT64_C(0x1476F63246AC884A), UINT64_C(0x568617D9EF46BED9),
    UINT64_C(0xE085162AB69D5E3C), UINT64_C(0xA275F7C11F7768AF),
    UINT64_C(0x6564D5FDE549331A), UINT64_C(0x279434164CA30589),
    UINT64_C(0xA9B6706FB8DFB2E3), UINT64_C(0xEB46918411358470),
    UINT64_C(0x2C57B3B8EB0BDFC5), UINT64_C(0x6EA7525342E1E956),
    UINT64_C(0x72E3DAA0AA188782), UINT64_C(0x30133B4B03F2B111),
    UINT64_C(0xF7021977F9CCEAA4), UINT64_C(0xB5F2F89C5026DC37),
    UINT64_C(0x3BD0BCE5A45A6B5D), UINT64_C(0x79205D0E0DB05DCE),
    UINT64_C(0xBE317F32F78E067B), UINT64_C(0xFCC19ED95E6430E8),
    UINT64_C(0x86B86ED5267CDBD3), UINT64_C(0xC4488F3E8F96ED40),
    UINT64_C(0x0359AD0275A8B6F5), UINT64_C(0x41A94CE9DC428066),
    UINT64_C(0xCF8B0890283E370C), UINT64_C(0x8D7BE97B81D4019F),
    UINT64_C(0x4A6ACB477BEA5A2A), UINT64_C(0x089A2AACD2006CB9),
    UINT64_C(0x14DEA25F3AF9026D), UINT64_C(0x562E43B4931334FE),
    UINT64_C(0x913F6188692D6F4B), UINT64_C(0xD3CF8063C0C759D8),
    UINT64_C(0x5DEDC41A34BBEEB2), UINT64_C(0x1F1D25F19D51D821),
    UINT64_C(0xD80C07CD676F8394), UINT64_C(0x9AFCE626CE85B507)
};

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc64_d_read(struct CRC64_d *dst, const void *src)
{
    assert(dst && src && "Non-null pointer");

    dst->hash[0] = cvt_byte_to_u64_be(src);
}

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc64_d_write(void *dst, const struct CRC64_d *src)
{
    assert(dst && src && "Non-null pointer");

    cvt_u64_be_to_byte(dst, src->hash[0]);
}

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc64_d_print(char *dst, const struct CRC64_d *src)
{
    int i, j;

    assert(dst && src && "Non-null pointer");

    for (i = 0; i != 1; ++i) {
        for (j = 16; j != 0; --j) {
            *(dst++) = hex_to_char(((src->hash[i]) >> (4 * j - 4)) & 0xF);
        }
    }

    *dst = '\0';
}

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc64_d_printw(wchar_t *dst, const struct CRC64_d *src)
{
    int i, j;

    assert(dst && src && "Non-null pointer");

    for (i = 0; i != 1; ++i) {
        for (j = 16; j != 0; --j) {
            *(dst++) = hex_to_wchar(((src->hash[i]) >> (4 * j - 4)) & 0xF);
        }
    }

    *dst = L'\0';
}

CRYPT_HASH_PREFIX uint8_t CRYPT_HASH_API crc64_d_less(const struct CRC64_d *lhs, const struct CRC64_d *rhs)
{
    assert(lhs && rhs && "Non-null pointer");

    return lhs->hash[0] < rhs->hash[0];
}

CRYPT_HASH_PREFIX uint8_t CRYPT_HASH_API crc64_d_eq(const struct CRC64_d *lhs, const struct CRC64_d *rhs)
{
    assert(lhs && rhs && "Non-null pointer");

    return lhs->hash[0] == rhs->hash[0];
}

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc64_cvt(struct CRC64_d *dst, const struct CRC64_c *src)
{
    int i;

    assert(dst && src && "Non-null pointer");

    for (i = 0; i != 1; ++i) {
        dst->hash[i] = src->hash[i];
    }
}

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc64_c_init(struct CRC64_c *val)
{
    assert(val && "Non-null pointer");

    val->hash[0] = UINT64_C(0xFFFFFFFFFFFFFFFF);
    val->length = 0;
    val->append = 1;
}

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc64_c_append(struct CRC64_c *val, const void *src, uint64_t len)
{
    const uint8_t *_src = src;
    const uint8_t *const _end = _src + len;
    uint64_t reg = val->hash[0];
    uint8_t cur_byte;

    assert(val && src && val->append && "Non-null pointer and append able");

    while (_end != _src) {
        cur_byte = (reg >> 56) ^ (*_src);
        reg <<= 8;
        reg ^= crc64_table[cur_byte];
        ++_src;
    }

    val->length += len;
    val->hash[0] = reg;
}

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc64_c_close(struct CRC64_c *val)
{
    assert(val && val->append && "Non-null pointer and append able");

    val->hash[0] = ~(val->hash[0]);
    val->append = 0;
}